#!/usr/bin/env python
# -*- coding:utf-8 -*-

import math
import re

from app import db
from flask import session
from controller.userInfoController import UserInfoController
from models.userInfoModel import UserInfo
from models.passageInfoModel import PassageInfo
from models.upvoteInfoModel import UpvoteInfo
from models.commentInfoModel import CommentInfo
from models.historyInfoModel import HistoryInfo
from sqlalchemy.orm import aliased
from sqlalchemy.sql import func
from utils import commons
from utils.rsa_encryption_decryption import RSAEncryptionDecryption
from utils.generate_id import GenerateID
from utils.response_code import RET, error_map_EN
from utils.loggings import loggings
import requests
import time


class UserInfoService(UserInfoController):
    @classmethod
    def joint_query(cls, **kwargs):
        try:
            filter_list = []
            filter_list.append(cls.IsDelete == 0)
            if kwargs.get('AutoID'):
                filter_list.append(cls.AutoID == kwargs.get('AutoID'))
            if kwargs.get('UserID'):
                filter_list.append(cls.UserID == kwargs.get('UserID'))
            if kwargs.get('UserOpenID'):
                filter_list.append(cls.Account == kwargs.get('Account'))
            if kwargs.get('FaceImg'):
                filter_list.append(cls.FaceImg == kwargs.get('FaceImg'))
            if kwargs.get('UserNickName'):
                filter_list.append(cls.UserNickName == kwargs.get('UserNickName'))
            if kwargs.get('IsDelete'):
                filter_list.append(cls.IsDelete == kwargs.get('IsDelete'))
            if kwargs.get('CreateTime'):
                filter_list.append(cls.CreateTime == kwargs.get('CreateTime'))
            if kwargs.get('ModifyTime'):
                filter_list.append(cls.ModifyTime == kwargs.get('ModifyTime'))

            page = int(kwargs.get('Page', 1))
            size = int(kwargs.get('Size', 10))

            userInfo_info = db.session.query(UserInfo.AutoID, UserInfo.UserID, UserInfo.Account, UserInfo.FaceImg,
                                             UserInfo.UserNickName, UserInfo.IsDelete, UserInfo.CreateTime,
                                             UserInfo.ModifyTime).filter(*filter_list)

            count = userInfo_info.count()
            pages = math.ceil(count / size)
            userInfo_info = userInfo_info.limit(size).offset((page - 1) * size).all()

            if not userInfo_info:
                return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data to update'}

            # 处理返回的数据
            results = commons.query_to_dict(userInfo_info)
            return {'code': RET.OK, 'message': error_map_EN[RET.OK], 'totalCount': count, 'totalPage': pages,
                    'data': results}

        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}
        finally:
            db.session.close()

    @classmethod
    def myquery(cls, userid):
        try:
            res = db.session.execute('select * from user_info where UserID = ' + userid)

            if not res:
                return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data to update'}
            res = [dict(zip(result.keys(), result)) for result in res]

            return {'code': RET.OK, 'message': error_map_EN[RET.OK], 'data': res}
        except Exception as e:
            # loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}


    @classmethod
    def user_loginv1(cls, **kwargs):
        user_account = kwargs.get('Account')
        user_password = kwargs.get('Password')
        filter_list = [cls.Account == user_account]
        try:
            user_info = db.session.query(cls).filter(*filter_list).first()
        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.LOGINERR, 'message': error_map_EN[RET.LOGINERR], 'error': "数据库连接异常，登录失败"}
        # 用户存在判断
        if not user_info:
            return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': '不存在该用户'}
        user_info = commons.query_to_dict(user_info)
        #密码校验
        if RSAEncryptionDecryption.decrypt(bytes(user_info.get('Password').encode())) != user_password:
            return {'code': RET.LOGINERR, 'message': error_map_EN[RET.LOGINERR], 'error': "密码错误"}

        user_id = user_info.get('UserID')
        user_type = user_info.get('UserType')

        #生成token
        from service.usertokenService import UserTokenService
        token = UserTokenService.create_token(user_id,user_type)

        back_data = {
            'UserID':user_id,
            'UserType':user_type,
            'Token':token
        }
        return {'code': RET.OK, 'message': error_map_EN[RET.OK], "data": back_data}

    @classmethod
    def user_login(cls, **kwargs):
        user_account = kwargs.get('Account')
        user_password = kwargs.get('Password')
        verify_code = kwargs.get('VerifyCode')
        print(verify_code)
        print(session.get('verifycode'))
        filter_list = [cls.Account == user_account]
        try:
            user_info = db.session.query(cls).filter(*filter_list).first()
        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.LOGINERR, 'message': error_map_EN[RET.LOGINERR], 'error': "数据库连接异常，登录失败"}
        # 用户存在判断
        if not user_info:
            return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': '不存在该用户'}
        user_info = commons.query_to_dict(user_info)
        # 密码校验
        if RSAEncryptionDecryption.decrypt(bytes(user_info.get('Password').encode())) != user_password:
            return {'code': RET.LOGINERR, 'message': error_map_EN[RET.LOGINERR], 'error': "密码错误"}
        # 验证码校验
        if verify_code != session.get('verifycode'):
            return {'code': RET.LOGINERR, 'message': error_map_EN[RET.LOGINERR], 'error': "验证码错误"}

        user_id = user_info.get('UserID')
        user_type = user_info.get('UserType')

        # 生成token
        from service.usertokenService import UserTokenService
        token = UserTokenService.create_token(user_id, user_type)

        back_data = {
            'UserID': user_id,
            'UserType': user_type,
            'Token': token
        }
        return {'code': RET.OK, 'message': error_map_EN[RET.OK], "data": back_data}

    @classmethod
    def commentme(cls, **kwargs):
        try:
            CommentUserInfo = aliased(UserInfo, name='CommentUserInfo')
            filter_list = [cls.IsDelete == 0, PassageInfo.IsDelete == 0, CommentInfo.IsDelete == 0,
                           CommentInfo.CommentParent.is_(None)]
            if kwargs.get('UserID'):
                filter_list.append(cls.UserID == kwargs.get('UserID'))
                filter_list.append(CommentInfo.CommentUserID != kwargs.get('UserID'))
            page = int(kwargs.get('Page', 1))
            size = int(kwargs.get('Size', 10))

            userInfo_info = db.session.query(PassageInfo.AutoID.label('PassageID'), PassageInfo.PostAuthorID,
                                             PassageInfo.PostTitle,
                                             PassageInfo.LookNUM, PassageInfo.CommentNum, PassageInfo.UpVoteNum,
                                             PassageInfo.PostType, PassageInfo.DeptType,
                                             CommentInfo.AutoID.label('CommentID'), CommentInfo.CreateTime,
                                             CommentInfo.CommentUserID, CommentUserInfo.UserNickName.label('CommentUserName'),
                                             CommentUserInfo.FaceImg, CommentInfo.IsRead,
                                             CommentInfo.CommentContent, CommentInfo.CreateTime).join(UserInfo,
                                                                                                      PassageInfo.PostAuthorID == UserInfo.UserID).join(
                CommentInfo, PassageInfo.AutoID == CommentInfo.CommentPostID).join(CommentUserInfo,CommentUserInfo.UserID == CommentInfo.CommentUserID).filter(*filter_list).order_by(
                CommentInfo.CreateTime.desc())

            count = userInfo_info.count()
            pages = math.ceil(count / size)
            userInfo_info = userInfo_info.limit(size).offset((page - 1) * size).all()

            if not userInfo_info:
                return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data to update'}

            # 处理返回的数据
            results = commons.query_to_dict(userInfo_info)
            # 调用该接口会让所有点赞信息置为已读
            from controller.commentInfoController import CommentInfoController

            for i in range(len(results)):
                update_data = {
                    'AutoID': results[i].get('CommentID'),
                    'IsRead': 1
                }
                CommentInfoController.update(**update_data)

                results[i].update(
                    {'CreateTime': int(time.mktime(time.strptime(results[i].pop('CreateTime'), "%Y-%m-%d %H:%M:%S")))})

            return {'code': RET.OK, 'message': error_map_EN[RET.OK], 'totalCount': count, 'totalPage': pages,
                    'data': results}

        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}
        finally:
            db.session.close()

    @classmethod
    def replyme(cls, **kwargs):
        try:
            ChildUser = aliased(UserInfo, name='ChildUser')
            ChildComment = aliased(CommentInfo, name='ChildComment')
            filter_list = [cls.IsDelete == 0, CommentInfo.IsDelete == 0, ChildComment.IsDelete == 0,
                           ChildUser.UserID != UserInfo.UserID]
            if kwargs.get('UserID'):
                filter_list.append(cls.UserID == kwargs.get('UserID'))

            userInfo_info = db.session.query(CommentInfo.AutoID, CommentInfo.CommentParent, CommentInfo.CommentUserID,
                                             UserInfo.UserNickName.label('CommentUserName'),
                                             CommentInfo.CommentPostID, CommentInfo.CommentContent,
                                             UserInfo.FaceImg, ChildComment.AutoID.label('ChildAutoID'),
                                             ChildUser.UserID.label('ReplyUserID'),
                                             ChildUser.UserNickName.label('ReplyUserName'),
                                             ChildUser.FaceImg.label('ReplyUserFaceImg'),
                                             ChildComment.CommentContent.label('ChildContent'), ChildComment.CreateTime,
                                             ChildComment.IsRead).join(UserInfo,
                                                                       CommentInfo.CommentUserID == UserInfo.UserID).join(
                ChildComment, ChildComment.CommentParent == CommentInfo.AutoID).join(ChildUser,
                                                                                     ChildUser.UserID == ChildComment.CommentUserID).filter(
                *filter_list).order_by(ChildComment.CreateTime.desc())

            count = userInfo_info.count()
            userInfo_info = userInfo_info.all()

            if not userInfo_info:
                return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data to update'}

            # 处理返回的数据
            results = commons.query_to_dict(userInfo_info)

            from controller.commentInfoController import CommentInfoController
            for i in range(len(results)):
                update_data = {
                    'AutoID': results[i].get('ChildAutoID'),
                    'IsRead': 1
                }
                CommentInfoController.update(**update_data)
                results[i].update(
                    {'CreateTime': int(time.mktime(time.strptime(results[i].pop('CreateTime'), "%Y-%m-%d %H:%M:%S")))})


            return {'code': RET.OK, 'message': error_map_EN[RET.OK], 'totalCount': count,
                    'data': results}

        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}
        finally:
            db.session.close()

    @classmethod
    def upvoteme(cls, **kwargs):
        try:
            UpvoteUser = aliased(UserInfo, name='UpvoteUser')
            filter_list = [cls.IsDelete == 0, UpvoteInfo.IsDelete == 0, PassageInfo.IsDelete == 0,
                           UpvoteInfo.UUserID != UserInfo.UserID]
            if kwargs.get('UserID'):
                filter_list.append(cls.UserID == kwargs.get('UserID'))

            page = int(kwargs.get('Page', 1))
            size = int(kwargs.get('Size', 10))

            userInfo_info = db.session.query(UserInfo.FaceImg, UserInfo.UserID, UserInfo.UserNickName,
                                             UpvoteInfo.CreateTime,
                                             UpvoteInfo.AutoID.label('ID'),
                                             UserInfo.UserNickName, PassageInfo.AutoID.label('PassageID'),
                                             PassageInfo.PostTitle,
                                             UpvoteInfo.UUserID, UpvoteInfo.IsRead,
                                             UpvoteUser.UserNickName.label('UpvoteNickName'),
                                             UpvoteUser.FaceImg.label('UpvoteFaceImg'),
                                             UpvoteUser.UserID.label('UpvoteUserID'),
                                             ).join(UserInfo, UserInfo.UserID == PassageInfo.PostAuthorID).join(
                UpvoteInfo, UpvoteInfo.PassageID == PassageInfo.AutoID).join(UpvoteUser,
                                                                             UpvoteUser.UserID == UpvoteInfo.UUserID).filter(
                *filter_list).order_by(
                UpvoteInfo.CreateTime.desc())

            count = userInfo_info.count()
            pages = math.ceil(count / size)
            userInfo_info = userInfo_info.limit(size).offset((page - 1) * size).all()

            if not userInfo_info:
                return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data to update'}

            # 处理返回的数据
            results = commons.query_to_dict(userInfo_info)
            for i in range(len(results)):
                results[i].update(
                    {'CreateTime': int(time.mktime(time.strptime(results[i].pop('CreateTime'), "%Y-%m-%d %H:%M:%S")))})

            # 调用该接口会让所有点赞信息置为已读
            from controller.upvoteInfoController import UpvoteInfoController
            for i in range(0, len(results)):
                update_data = {
                    'AutoID': results[i].get('ID'),
                    'IsRead': 1
                }

                UpvoteInfoController.update(**update_data)

            return {'code': RET.OK, 'message': error_map_EN[RET.OK], 'totalCount': count, 'totalPage': pages,
                    'data': results}

        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}
        finally:
            db.session.close()

    @classmethod
    def search_byname(cls, **kwargs):
        try:
            filter_list = [cls.IsDelete == 0]
            if kwargs.get('UserNickName'):
                querystr = '%{}%'.format(kwargs.get('UserNickName'))
                filter_list.append(cls.UserNickName.like(querystr))

            page = int(kwargs.get('Page', 1))
            size = int(kwargs.get('Size', 10))

            userInfo_info = db.session.query(UserInfo.AutoID, UserInfo.UserID, UserInfo.UserOpenID, UserInfo.FaceImg,
                                             UserInfo.UserNickName, UserInfo.IsDelete, UserInfo.CreateTime,
                                             UserInfo.ModifyTime).filter(*filter_list)

            count = userInfo_info.count()
            pages = math.ceil(count / size)
            userInfo_info = userInfo_info.limit(size).offset((page - 1) * size).all()

            if not userInfo_info:
                return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data to update'}

            # 处理返回的数据
            results = commons.query_to_dict(userInfo_info)
            return {'code': RET.OK, 'message': error_map_EN[RET.OK], 'totalCount': count, 'totalPage': pages,
                    'data': results}

        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}
        finally:
            db.session.close()

    @classmethod
    def recommend(cls, **kwargs):
        try:
            filter_list = [PassageInfo.IsDelete == 0, HistoryInfo.IsDelete == 0]

            if kwargs.get('UserID'):
                filter_list.append(cls.UserID == kwargs.get('UserID'))

            page = int(kwargs.get('Page', 1))
            size = int(kwargs.get('Size', 5))

            userInfo_info = db.session.query(PassageInfo.DeptType, func.count().label('num')).join(HistoryInfo,
                                                                                                   PassageInfo.AutoID == HistoryInfo.PassageID).join(
                UserInfo, UserInfo.UserID == HistoryInfo.HUserID).filter(*filter_list).group_by(
                PassageInfo.DeptType).order_by(func.count().desc())

            userInfo_info = userInfo_info.all()

            # 逻辑判断如果大于3种则根据其喜好进行推荐，否则选用随机推荐
            if len(userInfo_info) < 3:
                filter_list = [PassageInfo.IsDelete == 0, PassageInfo.PostAuthorID == UserInfo.UserID]
                page = int(kwargs.get('Page', 1))
                size = int(kwargs.get('Size', 10))
                passageInfo_info = db.session.query(PassageInfo.AutoID, PassageInfo.PostTitle, PassageInfo.CreateTime,
                                                    PassageInfo.PostContent, PassageInfo.CommentNum,
                                                    UserInfo.UserNickName).filter(*filter_list).order_by(
                    PassageInfo.CreateTime.desc())
                count = passageInfo_info.count()
                pages = math.ceil(count / size)
                passageInfo_info = passageInfo_info.limit(size).offset((page - 1) * size).all()

                if not passageInfo_info:
                    return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'No data'}
                # 处理返回的数据
                results = commons.query_to_dict(passageInfo_info)
                for i in range(len(results)):
                    results[i].update({'passageID': int(results[i].pop('AutoID'))})
                    results[i].update({'title': results[i].pop('PostTitle')})
                    results[i].update(
                        {'posttime': int(
                            time.mktime(time.strptime(results[i].pop('CreateTime'), "%Y-%m-%d %H:%M:%S")))})
                    img = re.search(r'(?<=(<img src=[\',"])).*?(?=([\',"]))', results[i]['PostContent'])
                    if (img):
                        results[i]['img'] = img.group().replace("&amp", "&").replace("&;", "&")
                    else:
                        results[i]['img'] = ''
                return {'code': RET.OK, 'message': error_map_EN[RET.OK],
                        'data': {'total': count, 'data': results}, 'totalPages': pages, 'totalcount': count}
            else:
                results = commons.query_to_dict(userInfo_info)
                data_list = []
                for i in range(3):
                    data_list.append(results[i].get('DeptType'))
                filter_list2 = [PassageInfo.DeptType.in_(data_list),PassageInfo.IsDelete == 0,PassageInfo.CreateTime.desc()]
                filter_list3 = [PassageInfo.DeptType.not_in(data_list),PassageInfo.IsDelete == 0,PassageInfo.CreateTime.desc()]
                recommend_info = db.session.query(PassageInfo.AutoID, PassageInfo.PostTitle, PassageInfo.CreateTime,
                                                  PassageInfo.PostContent, PassageInfo.CommentNum,
                                                  UserInfo.UserNickName).join(UserInfo,
                                                                              UserInfo.UserID == PassageInfo.PostAuthorID).filter(*filter_list2
                    )

                recommend_info2 = db.session.query(PassageInfo.AutoID, PassageInfo.PostTitle, PassageInfo.CreateTime,
                                                  PassageInfo.PostContent, PassageInfo.CommentNum,
                                                  UserInfo.UserNickName).join(UserInfo,
                                                                              UserInfo.UserID == PassageInfo.PostAuthorID).filter(*filter_list3
                    )
                count = recommend_info.count()
                count2 = recommend_info2.count()
                print(count2)
                pages = math.ceil((count+count2) / (size*2))
                recommend_info = recommend_info.limit(size).offset((page - 1) * size).all()
                recommend_info2 = recommend_info2.limit(size).offset((page - 1) * size).all()
                recommend_info = recommend_info+recommend_info2
                if not recommend_info:
                    return {'code': RET.NODATA, 'message': error_map_EN[RET.NODATA], 'error': 'NO Passage in it'}
                recommend_info = commons.query_to_dict(recommend_info)
                for i in range(len(recommend_info)):
                    recommend_info[i].update({'passageID': int(recommend_info[i].pop('AutoID'))})
                    recommend_info[i].update({'title': recommend_info[i].pop('PostTitle')})
                    recommend_info[i].update(
                        {'posttime': int(
                            time.mktime(time.strptime(recommend_info[i].pop('CreateTime'), "%Y-%m-%d %H:%M:%S")))})
                    img = re.search(r'(?<=(<img src=[\',"])).*?(?=([\',"]))', recommend_info[i]['PostContent'])
                    if (img):
                        recommend_info[i]['img'] = img.group().replace("&amp;", "&").replace("&;", "&")
                    else:
                        recommend_info[i]['img'] = ''
                return {'code': RET.OK, 'message': error_map_EN[RET.OK],
                        'data': recommend_info}


        except Exception as e:
            loggings.exception(1, e)
            return {'code': RET.DBERR, 'message': error_map_EN[RET.DBERR], 'error': str(e)}
        finally:
            db.session.close()
